<?php
/**
 * Created by PhpStorm.
 * User: wanghaibo
 * Date: 18/3/26
 * Time: 16:45
 */

namespace App\Services\Admin;


use App\Models\Account;
use App\Models\User;
use App\Models\UserWallet;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Laravel\Passport\Bridge\AccessTokenRepository;
use Laravel\Passport\Bridge\Client;
use League\OAuth2\Server\CryptKey;
use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;

class UserService
{
    use ChartTrait;
    protected $repo;
    protected $model;
    public function __construct()
    {
        $this->model = new User();
    }
    public function issueJWTToken($user_id){

        $ttl = new \DateInterval('PT1H');
        $ttl->y =1;

        $client = new Client(env('PASS_PORT_ID'),env('PASS_PORT_NAME'),env('PASS_PORT_REDIRECT'));

        $scopes =[];
        $id =$user_id;

        $repo = resolve('Laravel\Passport\Bridge\AccessTokenRepository');
        $maxGenerationAttempts = 10;
        $accessToken = $repo->getNewToken($client, $scopes, $id);
        $accessToken->setClient($client);
        $accessToken->setUserIdentifier($id);
        $accessToken->setExpiryDateTime((new \DateTime())->add($ttl));

        foreach ($scopes as $scope) {
            $accessToken->addScope($scope);
        }

        while ($maxGenerationAttempts-- > 0) {
            $accessToken->setIdentifier($this->generateUniqueIdentifier());
            try {
                $repo->persistNewAccessToken($accessToken);

                $key = new CryptKey('file://'.storage_path('oauth-private.key'),null,false);

                return (string)$accessToken->convertToJWT($key);
            } catch (UniqueTokenIdentifierConstraintViolationException $e) {
                if ($maxGenerationAttempts === 0) {
                    throw $e;
                }
            }
        }
    }
    public function generateUniqueIdentifier($length = 40){
        try {
            return bin2hex(random_bytes($length));
            // @codeCoverageIgnoreStart
        } catch (\TypeError $e) {
            throw OAuthServerException::serverError('An unexpected error has occurred');
        } catch (\Error $e) {
            throw OAuthServerException::serverError('An unexpected error has occurred');
        } catch (\Exception $e) {
            // If you get this message, the CSPRNG failed hard.
            throw OAuthServerException::serverError('Could not generate a random string');
        }
    }
    public function lists(Request $request){
        $model = $this->model;
        $keywords = $request->input('keywords','');
        if($keywords){
            return $model->with('wallet')->where('id','>',1)
                ->where(function($query) use ($keywords){
                    $query->
                    where('name','like','%'.$keywords.'%')
                        ->orWhere('mobile','like','%'.$keywords.'%')
                        ->orWhere('remark','like','%'.$keywords.'%');
                })->paginate(10);
        }
        return $model->with('wallet')->where('id','>',1)->paginate(10);
    }
    public function getUser($id){
        $model = $this->model;
        return $model->with('wallet')->where('id','>',1)->find($id);
    }
    public function charge($id,$amount,$note=''){
        $model = $this->model;
        $user = $model->find($id);
        if(!$user){
            return false;
        }
        DB::transaction(function () use($user,$amount,$note){
            $wallet = new UserWallet();
            $wallet->where('user_id',$user->id)->increment('amount',$amount);
            $user->account()->create([
                'amount'    =>  $amount,
                'type'  => Account::TYPE_CHARGE,
                'note'  =>  $note
            ]);
        });

    }
    public function cost($id,$amount,$note=''){
        $model = $this->model;
        $user = $model->find($id);
        if(!$user){
            return false;
        }
        DB::transaction(function () use($user,$amount,$note){
            $wallet = new UserWallet();
            $wallet->where('user_id',$user->id)->increment('amount',$amount);
            $user->account()->create([
                'amount'    =>  $amount,
                'type'  => Account::TYPE_COST,
                'note'  =>  $note
            ]);
        });

    }
    public function update(Request $request,$user_id){
        $model = $this->model;
        $user = $model->find($user_id);
        return $user->fill($request->input())->save();
    }
    public function destroy($user_id){
        $model = $this->model;
        return $model->find($user_id)->delete();
    }
    public function add(Request $request){
        DB::transaction(function () use($request){
            $model = $this->model;
            $user = $model->create(
                [
                    'name'  =>  $request->input('name'),
                    'mobile'   =>   $request->input('mobile',''),
                    'remark'    =>  $request->input('remark',''),
                    'email' =>  $request->input('email'),
                    'password'  =>  Hash::make('111111')
                ]
            );
            $user->wallet()->create(
                [
                    'amount'    =>  0.00
                ]
            );
        });
    }
    public function count($type){
        $model = $this->model;
        $model = $model->where('id','<>',1);
        $count = 0;
        switch ($type){
            case 'all':
                $count = $model->count('id');
                return $count;
            case 'yesterday':
                $count = $model->whereBetween('created_at',[Carbon::yesterday(),Carbon::today()])->count('id');
                break;
        }
        return $count;
    }
    public function getCharts($type){
        $groupBy = $this->getGroupBy($type);
        $model = $this->model;
        $model = $model->where('id','<>',1);
        $model = $model->select(DB::raw('count(id) as _res,'.$groupBy.'as _time'));
        $timeRange = $this->getDateRange($type);
        $model = $model->whereBetween('created_at',$timeRange);
        $model = $model->groupBy(DB::raw($groupBy));
        $model = $model->orderBy('_time','ASC');
        $data = $model->get();
        return $this->parseData($data,$type);
    }
}